package com.mini.rpc.provider.registry.loadbalancer;

import com.mini.rpc.common.ServiceMeta;
import com.mini.rpc.provider.registry.exception.NoAvailableProviderException;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 轮序负载均衡算法
 *
 * @author: hliushi
 * @date: 2022/4/24 9:25
 **/
public class RoundRobinLoadBalancer implements ServiceLoadBalancer<ServiceMeta> {
    private final AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     * 轮序负载均衡算法获取一个节点
     *
     * @param servers  服务节点列表
     * @param hashCode 客服端节点的hashCode
     * @return 服务节点实例
     */
    @Override
    public ServiceMeta select(List<ServiceMeta> servers, int hashCode) {
        // 当服务提供者没有启动, 导致 servers.size() == 0, 会出现  ArithmeticException: / by zero
        if (servers.size() == 0) {
            throw new NoAvailableProviderException("no available provider");
        }
        int index = getAndIncrement() % servers.size();
        return servers.get(index);
    }

    /**
     * 防止Integer越界 超过Integer最大值
     */
    private int getAndIncrement() {
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1;
        } while (!this.atomicInteger.compareAndSet(current, next));
        return next;
    }
}
